#include "app_buffer.h"
#include "stdio.h"
#include "stdlib.h"
#include"log.h"
#include"string.h"
#include"app_common.h"
#define APP_BUFFER_MAX_LEN 1024

/**
 * @brief 创建缓冲区
 * @return app_buffer_t
 */

app_buffer_t *app_buffer_init()
{
    // 1.创建主缓冲区结构体
    app_buffer_t *buffer = (app_buffer_t *)malloc(sizeof(app_buffer_t));

    // 2.创建子缓冲区结构体
    for (int i = 0; i < 2; i++)
    {   
        buffer->sub_buffer[i] = (sub_app_buffer_t *)malloc(sizeof(sub_app_buffer_t));
        buffer->sub_buffer[i]->data_ptr = (char *)malloc(APP_BUFFER_MAX_LEN);
        buffer->sub_buffer[i]->data_len = 0;
        buffer->sub_buffer[i]->total_len = APP_BUFFER_MAX_LEN;
    }
    // 3.设定读写下标
    buffer->read_index = 0;
    buffer->write_index = 1;
    pthread_mutex_init(&buffer->read_lock, NULL);
    pthread_mutex_init(&buffer->swap_lock, NULL);


    return buffer;
}

/**
 * 切换读写缓冲区
 */
void app_buffer_swap(app_buffer_t *buffer)
{
    pthread_mutex_lock(&buffer->swap_lock);
    buffer->read_index = buffer->read_index==0?1:0;
    buffer->write_index = buffer->write_index==0?1:0;
    pthread_mutex_unlock(&buffer->swap_lock);
}

 /**
 * 向缓冲区写入数据
 * @param buffer 缓冲区指针
 * @return 0:成功, -1:失败
 */
int app_buffer_write(app_buffer_t *buffer, char *write_data, int write_data_len){

    log_info("app_buffer_write:  写入数据:\n");
    app_common_print_hex(write_data,write_data_len);
    //多线程的时候要锁住不能同时写 
    pthread_mutex_lock(&buffer->swap_lock);
    //1.获取的当前写子缓冲区指针
    sub_app_buffer_t *write_sub_buffer = buffer->sub_buffer[buffer->write_index];
    //2.写入数据 (1.数据长度作为帧头  2.数据内容作为帧体)
    int remain_len = write_sub_buffer->total_len - write_sub_buffer->data_len;
    if(write_data_len+1>remain_len){
        log_error("缓冲区空间不足");
        pthread_mutex_unlock(&buffer->swap_lock);
        return -1;
    }
    //3.增加缓冲区的数据长度  data_ptr[当前数据长度] 
    write_sub_buffer->data_ptr[write_sub_buffer->data_len]=write_data_len; //写入数据长度作为帧头
    //拷贝到 写子的缓冲区的当前长度+1的位置
    memcpy(write_sub_buffer->data_ptr+write_sub_buffer->data_len+1,write_data,write_data_len);//写入数据内容作为帧体
    //写缓冲区当前数据长度增加 （+1）是因为加了一个帧头
    write_sub_buffer->data_len+=write_data_len+1;
    pthread_mutex_unlock(&buffer->swap_lock);
    return 0;
}

/**
 * 向缓冲区读数据
 * @param 缓冲区指针
 * @param read_data 读数据指针
 * @param read_data_len 读数据长度
 * @return 读成功返回实际长度
 */

int app_buffer_read(app_buffer_t *buffer, char *read_buff, int read_buff_len){

    //加锁线程的时候要锁住不能同时读
    pthread_mutex_lock(&buffer->read_lock);
    //1. 获取负责读的子缓冲区指针
    sub_app_buffer_t *read_sub_buffer = buffer->sub_buffer[buffer->read_index];
    //2. 判断是否存在数据
    if(read_sub_buffer->data_len==0){ 
    //  2.1 没有数据要进行缓冲区的切换
        app_buffer_swap(buffer);
    //  2.2 再次获取负责读的子缓冲区
        read_sub_buffer = buffer->sub_buffer[buffer->read_index];
    //  2.3 判断是否有数据
        if(read_sub_buffer->data_len==0){
            printf("app_buffer_read:  没有数据\n");
            pthread_mutex_unlock(&buffer->swap_lock);
            return 0;
        }
    }
    
    // 3.  有数据
    //   3.1 获取祯头  每次都要在data_ptr[0]位置获取从最上面获取数据长度 
    int read_len=read_sub_buffer->data_ptr[0];
    //   3.2 比较要读取的数据长度和和读取数据容器的长度
    if(read_len>read_buff_len){ //若子缓冲区数据长度大于读取数据容器的长度 
        log_error("缓冲区空间不足");
        pthread_mutex_unlock(&buffer->swap_lock);
        return -1;
    }
    //   3.3 读取数据  1把数据内容读取到数据容器 2.后面的数据覆盖前面数据  3.调整数据长度
    memcpy(read_buff,read_sub_buffer->data_ptr+1,read_len); //读取read_len长度的数据
    int rm_size=read_len+1;
    // 3.4 数据覆盖    dest指向最前面       src指向删除数据的下边                 移动多少
    memmove(read_sub_buffer->data_ptr,read_sub_buffer->data_ptr+rm_size,read_sub_buffer->data_len-rm_size);
    read_sub_buffer->data_len -= rm_size;
    pthread_mutex_unlock(&buffer->read_lock);
   
    // 4. 返回实际读取的长度
    return read_len;
    
}










// /**
//  * @brief 向缓冲区写入数据
//  * @param app_buffer_t* 缓冲区指针
//  * @return int 写入成功返回0，失败返回-1
//  * 步骤：
//  *  1 获取当前负责写的子缓冲区指针
//  *  2 写入数据 （1 数据长度作为帧头， 2 数据内容作为帧体）
//  *  3 增加缓冲区数据长度
//  */
// int app_buffer_write(app_buffer_t *buffer, char *write_data, int write_data_len)
// {
//     pthread_mutex_lock(&buffer->swap_lock);
// //  *  1 获取当前负责写的子缓冲区指针
//     sub_app_buffer_t *write_sub_buffer = buffer->sub_buffer[buffer->write_index];
    
// //  *  2 写入数据 （1 数据长度作为帧头， 2 数据内容作为帧体）
//     int remain_len=write_sub_buffer->total_len-write_sub_buffer->data_len;
//     if(write_data_len+1>remain_len)
//     {
//         pthread_mutex_unlock(&buffer->swap_lock);
//         log_error("剩余缓冲区长度不足");
//         return -1;
//     }
//     write_sub_buffer->data_ptr[write_sub_buffer->data_len]=write_data_len;//写入数据长度作为帧头
//     memcpy(write_sub_buffer->data_ptr+write_sub_buffer->data_len+1,write_data ,write_data_len); //写入帧体

// //  *  3 增加缓冲区数据长度
//     write_sub_buffer->data_len+=write_data_len+1;

//     pthread_mutex_unlock(&buffer->swap_lock);
//      return 0;

// }

// /**
//  * @brief 从缓冲区读取数据
//  * @param app_buffer_t* 缓冲区指针
//  * @param  char* 读取数据容器
//  * @param int 读取数据容器长度
//  * @return int 读取成功返回 实际的数据长度，失败返回-1
//  * 步骤：
//  * 1 获取负责读的子缓冲区 
//  * 2 判断是否有数据 
//  *      2.1 没有数据  要进行缓冲区的切换
//  *      2.2 再次 获取负责读的子缓冲区 
//  *      2.3 检查是否有数据 如果确实没有 返回0 
//  *  3 有数据  读取数据
//  *      3.1  取最顶上的帧头 
//  *      3.2  比较要读取的数据长度和  读取数据容器的长
//  *      3.3  读取数据 （1 把数据内容读取到数据容器中 2 后面的数据覆盖前面的 3 调整缓冲区数据长度）
//  *  4 返回实际读取的长度
//  *      
//  *   
//  */
// int app_buffer_read(app_buffer_t *buffer, char *read_buff, int read_buff_len)
// {
//     //A 此处加锁 
//     pthread_mutex_lock(&buffer->read_lock);
//     // * 1 获取负责读的子缓冲区 
//     sub_app_buffer_t *read_sub_buffer = buffer->sub_buffer[buffer->read_index];
//     // * 2 判断是否有数据 
//     //B 1
//     if(read_sub_buffer->data_len == 0)
//     {
//     // *      2.1 没有数据  要进行缓冲区的切换
//           app_buffer_swap(buffer);
//     // *      2.2 再次 获取负责读的子缓冲区 
//           read_sub_buffer = buffer->sub_buffer[buffer->read_index];
//     // *      2.3 检查是否有数据 如果确实没有 返回0 
//           if(read_sub_buffer->data_len == 0)
//           {
//              pthread_mutex_unlock(&buffer->read_lock);
//               return 0;
//           }
//     }
//   //C
//     // *  3 有数据  读取数据
//     // *      3.1  取最顶上的帧头 
//           int read_len =  read_sub_buffer->data_ptr[0];
//     // *      3.2  比较要读取的数据长度和  读取数据容器的长
//           if(read_len > read_buff_len)
//           {
//             pthread_mutex_unlock(&buffer->read_lock);
//               log_error("读取容器空间不足");
//               return -1;
//           }
//   //D
//     // *      3.3  读取数据 （1 把数据内容读取到数据容器中 2 后面的数据覆盖前面的 3 调整缓冲区数据长度）
//           memcpy(read_buff,read_sub_buffer->data_ptr+1,read_len);
//           int rm_size=read_len+1;
//           memmove(read_sub_buffer->data_ptr,read_sub_buffer->data_ptr+rm_size,read_sub_buffer->data_len -rm_size);
//           read_sub_buffer->data_len -= rm_size;
//     //E
//     pthread_mutex_unlock(&buffer->read_lock);
//     // *  4 返回实际读取的长度
//           return read_len;
// }













/**
 * 销毁缓冲区
 */
void app_buffer_destroy(app_buffer_t *buffer){
    if(buffer)
    {
        for (size_t i = 0; i < 2; i++)
        {
            if(buffer->sub_buffer[i])
            {
                free(buffer->sub_buffer[i]->data_ptr);
                free(buffer->sub_buffer[i]);
            }
        }
        pthread_mutex_destroy(&buffer->read_lock);
        pthread_mutex_destroy(&buffer->swap_lock);
        free(buffer);
    }

}